#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>


//1


//int main()
//{
//	int a = 10000;
//	//内存里是补码，内存里是小端字节序排放，正数原码等于补码
//	//0000 0000 0000 0000 0010 0111 0001 0000
//	// 0    0    0    0    2    7    1    0
//	//二进制存放，十六进制显示，大端字节序显示
//	//10 27 00 00
//	FILE* pf = fopen("text.txt", "wb");//以二进制写的方式打开这个文件出其内存指针
//	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
//
//	//二进制文件显示
//	//10 27 00 00
//	//二进制存放，十六进制显示，大端字节序显示
//	fclose(pf);
//	return 0;
//}


//2 打开关闭文件


//int main()
//{
//	//1.打开文件
//	//打开文件成功的话，返回的是有效的指针
//	//如果打开失败，则返回NULL
//	FILE* pf = fopen("text.txt", "w");//只写文件操作打开文件，如果文本文件存在会把文件里的内容清空，如果文本文件不存在会新建一个文本文件
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//
//
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}
//
//int main()
//{
//	FILE* pf2 = fopen("data.txt", "r");//只读文件操作打开文件，如果文本文件不存在会出错
//	if (pf2 == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//打开后接下来的操作是把文件里的内容放到程序的内存里，读文件
//	 
//	
//	//关闭文件
//	fclose(pf2);
//	pf2 = NULL;
//	return 0;
//}
//
//int main()
//{
//	FILE* pf3 = fopen("C:\\Users\\32868\\Desktop\\test.txt", "w");//无路径找的是此文件夹里面的文件，加了具体路径就能找到那里的文件
//	//                绝对路径
//	if (pf3 == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	fclose(pf3);
//	pf3 = NULL;
//	return 0;
//}
//
//int main()
//{
//	FILE* pf4 = fopen(".\\..\\..\\test2.txt", "w");
//	//                相对路径
//	//. 表示当前路径
//	//.. 表示上一级路径
//	if (pf4 == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	fclose(pf4);
//	pf4 = NULL;
//	return 0;
//}


//                         标准输出流、文件输出流
//3 fputc字符输出函数，适用于所有输出流，写字符，写的是文本信息
//int fputc ( int character, FILE * stream );
//Write character to stream
//写入字符到流


//int main()
//{//           打开流
//	FILE* pf = fopen("text.txt", "w");//以写的形式打开文件，就只能写
//	if (pf == NULL)//以写的形式有没有文件都能打开成功
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	for (int i = 'a';i<='z';i++)
//	{//文件与程序在程序里的互通介质 ->流
//		fputc(i, pf);//输出程序到文件不一定要从程序的内存里的
//	}//这些函数从流里取东西放东西到流与程序里的流操作的
//
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//                      标准输入流、文件输入流
//4 fgetc字符输入函数，适用于所有输入流，读字符，读的是文本信息
//int fgetc(FILE* stream);
//Get character from stream
//从流中获取字符
//读取正常的时候，返回读取到的字符的ASCII码值
//读取失败(包括读到文件末尾)的时候，会返回EOF(本质是-1)


//int main()
//{                  //以读的形式没有文件的话会打开失败
//	FILE* pf = fopen("text.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	int ch = 0;
//	while ((ch = fgetc(pf)) != EOF)
//	{//从流里读字符读到的靠函数返回值到程序
//		printf("%c ", ch);
//	}
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//5 屏幕键盘文件的流是一直开着的不用去开也不用去关


//int main()
//{//键盘这个文件的流stdin是不用开关的
//	int ch = fgetc(stdin);//从键盘(标准输入流)上读取
//	fputc(ch, stdout);//将字符输出(写)到屏幕(标准输出流)
//	//屏幕这个文件的流stdout是不用开关的
//	return 0;
//}


//6 fputs文本行输出函数，适用于所有输入流 //输入输出都是相对程序而言的
//            是个字符指针
//int fputs(const char* str, FILE* stream);
//输出成功返回非负的整数，失败返回EOF
//Write string to stream
//写入字符串到流


//int main()
//{
//	FILE* pf = fopen("text.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	fputs("\nI am a student\n", pf);
//	//也全写，写的是第182这一行""里的全部文本
//	fputs("Hello", pf);
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//7 fgets文本行输入函数，适用于所有输入流，只读取一行的数据，遇文本里的\0会停
//       读到的字符串会拷贝放到这个字符数组里 //读的是字符串的话得安排个空间放
//              char* fgets     (char* str,                  int num,    FILE* stream);
//(输入成功)返回读取到放的字符数组的指针   最大读到取拷贝字符数(要包括上fgets函数自己最后加的\0字符)
//失败的话返回空指针
//Get string from stream   
//从流中获取字符串


//int main()
//{
//	FILE* pf = fopen("text.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	char arr[20] = { 0 };
//	fgets(arr, 20, pf);//fgets函数最多往里读取放入20个字符，字符数组空间20个大小不会放不下，但输入的必有\0，最多的话19个文本里的字符
//	printf("%s\n", arr);
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//8


//int main()
//{
//	char arr[20] = { 0 };
//	fgets(arr, 20, stdin);
//	fputs(arr, stdout);
//	return 0;
//}


//fget、fput类的函数是针对字符文本类数据的，与字符相关的
//9 fprintf格式化输出函数，适用于所有输出流，可以针对不仅字符的所有数据
//                                       可变参数列表，参数没有固定几个，参数的个数可变的(ptintf、scanf函数)
//int fprintf(FILE* stream,const char* format,...);
//在printf基础上多一个流参数就可以了(printf默认stdout流不用写传)  
//Write formatted data to stream
//将格式化数据写入流


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	char name[20] = "zhangsan";
//	int age = 20;
//	float score = 95.5f;
//	struct S s = { "lisi",18,88.0f };
//	FILE* pf = fopen("text.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	fprintf(pf, "%s %d %.1f\n", name, age, score);
//	fprintf(pf, "%s %d %.1f", s.name, s.age, s.score);
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//10 fscanf格式化输入函数，适用于所有输入流，可以针对所有类型数据
//int fscanf(FILE* stream, const char* format, ...);
//读取成功返回读取到的个数(可以比预期少或者0)，读取发生错误失败返回EOF
//int scanf ( const char * format, ... ); //scanf默认stdin流不用写传
//Read formatted data from stream
//从流中读取格式化数据


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct S s = { 0 };
//	FILE* pf = fopen("text.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}//scanf函数输入也得有空间放，除了fgetc函数输入不用安排空间放
//	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
//	printf("%s %d %.1f", s.name, s.age, s.score);
//	return 0;
//}


//11 sprintf，不用标准流(到屏幕)与文件流(到文件),它是到程序的，把格式化的数据转化成字符串，内容直接变成字符串内容，从程序输出到的文件改成程序的字符串里，写到不是流里，写到字符数组里，不涉及文件操作，都是在程序内部
//int sprintf(char* str, const char* format, ...);
//Write formatted data to string
//将格式化数据写入字符串

//sscanf从的文件改成程序的字符串内容输入到程序，不涉及文件操作，都是在程序内部
//int sscanf ( const char * s, const char * format, ...);
//Read formatted data from string
//读取字符串中的格式化数据


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	char arr[100] = { 0 };
//	struct S s = { "wangwu",23,66.6f };
//
//	//临时变量
//	struct S tmp = { 0 };
//
//	//将s中的各个数据转换成字符串，存放在arr中
//	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
//	//printf("%s\n", arr);
//
//	//从字符串arr中提取格式化的数据，存放在tmp中，从arr中按照这种格式搜索内容存入到地址对应内存中
//	sscanf(arr, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));//以前的scanf键盘上来数据输入的，此流一直开的不用操作流默认对向此流//scanf搜索的一直都是已化为字符串类的数据文本
//	printf("%s %d %f", tmp.name, tmp.age, tmp.score);
//	return 0;
//}


//12 fwrite二进制输出函数，适用于的仅文件输出流
//size_t fwrite(const void* ptr, size_t size,   size_t count, FILE* stream);
//                内存块头地址  每个元素的大小    元素的个数
//Write block of data to stream
//将数据块写入流


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct S s = { "cuihua",25,88.8f };
//	//以二进制的形式写到文件中
//
//	//1.打开文件
//	FILE* pf = fopen("text.txt", "wb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//2.写文件 //结构体看作了一个元素的数组
//	fwrite(&s, sizeof(struct S), 1, pf);
//
//	//3.关闭文件
//	fclose(pf);
//	pf == NULL;
//	return 0;
//}


//13 fread二进制输入函数，适用于仅文件输出流
//size_t fread(void* ptr, size_t size, size_t count, FILE* stream);
//Read block of data from stream
//读取流中的数据块


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//int main()
//{
//	struct S s = { 0 };
//	//将二进制文件里的二进制读进程序来存到s里面
//
//	//1.打开文件
//	FILE* pf = fopen("text.txt", "rb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//2.读文件
//	fread(&s, sizeof(struct S), 1, pf);
//
//	printf("%s %d %f\n", s.name, s.age, s.score);
//
//	//3.关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//14 实现文件随机读写函数 fseek ftell rewind
//fseek,根据文件指针的位置和偏移量来定位文件指针(文化内容的光标)函数，是实现文件的随机读写函数之一
//int fseek(FILE* stream, long int offset,   int origin);
                       //偏移量(可正可负)   //起始位置(自己定的)
//Reposition stream position indicator
//重置流位置指示器
//offset的3个参数
//SEEK_SET	Beginning of file  文件开头位置
//SEEK_CUR	Current position of the file pointe 当前文件指针位置
//SEEK_END	End of file* 文件末尾位置

//ftell获取文件指针相对于起始位置的偏移量函数
//long int ftell(FILE* stream);
//Get current position in stream
//获取流中的当前位置

//rewind将文件指针定位到文件起始位置的函数
//void rewind(FILE* stream);
//Set position of stream to the beginning
//设置流的位置到开始


//int main()
//{
//    //1.打开文件（abcdef）
//    FILE* pf = fopen("text.txt", "r");
//    if (pf == NULL)
//    {
//        perror("fopen");
//        return 1;
//    }
//    //2.读文件
//    int ch = 0;
//    //fgetc的顺序读写
//    //读写函数都是顺序的，随机读写的实现靠其它专门移动文件指针的函数实现
//    ch = fgetc(pf);//a
//    printf("%c\n", ch);
//    ch = fgetc(pf);//b,fgetc函数完成读取光标所指内容后也完成光标后移一次
//    //此时光标指向c(3)
//    printf("%c\n", ch);
//
//
//    //fseek函数来移动文件指针,仅实现了移动光标
//    
//                              //偏移量即步数即只算一头数等于位置数相减
//    //fseek(pf, 4, SEEK_SET);//文件刚开始时指向a，1+4=5指向了e
//    //程序操作文件都是操作文件传过来的流
//    //fseek(pf, 2, SEEK_CUR);//3+2=5
//    fseek(pf, -2, SEEK_END);//末尾不是指向f，而是指向f还后一个还没来的//7-2=5
//    ch = fgetc(pf);//e，fgetc读完光标所指内容后再将光标后移一位
//    //此时指向了f(6)
//    printf("%c\n", ch);
//    
//    //ftell输出文件指针相较于文件的起始位置(1)的偏移量
//    int ret = ftell(pf);//6-1=5;
//    printf("%d\n", ret);
//
//    //rewind将文件指针重新定位到文件的起始位置
//    rewind(pf);
//    ch = fgetc(pf);//a
//    printf("%c\n", ch);
//
//
//    //3.关闭文件
//    fclose(pf);
//    pf = NULL;
//    return 0;
//}


//15 检测读取失败原因的函数 ferror feof 读取失败时，程序会向流里设置错误信息，它们检测流里的错误的信息是哪种
//ferror检测读取失败的原因是否是读取错误函数
//int ferror(FILE* stream);
//如果是读取错误，返回非零指，如果不是，返回0
//Check error indicator  检查错误指示器
//Checks if the error indicator associated with stream is set, returning a value different from zero if it is.
//检查与流关联的错误指示器是否已设置，如果是，则返回一个非零值


//拷贝文件
//test.txt --> test2.txt

//int main()
//{
//    //打开文件
//    FILE* pfread = fopen("test1.txt", "r");
//    if (pfread == NULL)
//    {
//        perror("fopen");
//        return 1;
//    }
//    FILE* pfwrite = fopen("test2.txt", "w");
//    if (pfwrite == NULL)
//    {
//        perror("fopen");
//        return 2;
//    }
//
//    //读/写文件
//    int ch = 0; //读进程序(没到内存最多ch存了一下)
//    while ((ch = fgetc(pfread)) != EOF)
//    {    //读到程序里的内容写到test2.txt文件
//        fputc(ch, pfwrite);
//    }
//    //到这里时ch = EOF，发生了读取失败，检测读取错误的原因
//    int ret;
//    if (ret = feof(pfread))
//    printf("遇到文件末尾而读取失败\n");
//    if (ret = ferror(pfread))
//    printf("读取文件的时候发生读取错误而失败\n");
//
//    //关闭文件
//    fclose(pfread);
//    pfread = NULL;
//    fclose(pfwrite);
//    pfwrite = NULL;
//    return 0;
//}


//16 文件缓冲区


//#include<Windows.h>
//int main()
//{
//    FILE* pf = fopen("text.txt", "w");
//    fputs("abcdef", pf);//它的写操作其实还是先写在内存里的文件缓冲区里的，等到后面刷新文件缓冲区时才写到文件
//    Sleep(10000);//睡眠10秒，此时文件里是没有内容的
//    fflush(pf);//刷新文件缓冲区
//    Sleep(10000);//此时内容已经写到文件里了
//    fclose(pf);//fclose在关闭文件的时候，也会刷新缓冲区
//    pf = NULL;
//    return 0;
//}